import 'package:dio/dio.dart';
import 'base_http_client.dart';
import 'config/api_config.dart';
import 'exceptions/app_exceptions.dart';
import 'interceptors/logging_interceptor.dart';
import 'interceptors/retry_interceptor.dart';
import 'interceptors/auth_interceptor.dart';
import 'models/api_response.dart';

class HttpClient extends BaseHttpClient {
  late Dio _dio;
  final Map<String, CancelToken> _cancelTokens = {};
  final List<Interceptor> _customInterceptors = [];

  HttpClient() {
    _initDio();
  }

  void _initDio() {
    _dio = Dio(BaseOptions(
      baseUrl: ApiConfig.baseUrl,
      connectTimeout: ApiConfig.connectTimeout,
      receiveTimeout: ApiConfig.receiveTimeout,
      sendTimeout: ApiConfig.sendTimeout,
      headers: ApiConfig.defaultHeaders,
    ));

    // 添加默认拦截器
    _addDefaultInterceptors();
  }

  void _addDefaultInterceptors() {
    // 先清空所有拦截器
    _dio.interceptors.clear();

    // 添加默认拦截器
    _dio.interceptors.addAll([
      LoggingInterceptor(),
      RetryInterceptor(),
    ]);

    // 添加自定义拦截器
    _dio.interceptors.addAll(_customInterceptors);
  }

  // ============ 实现 BaseHttpClient 抽象方法 ============

  @override
  void setBaseUrl(String baseUrl) {
    _dio.options.baseUrl = baseUrl;
  }

  @override
  void setHeaders(Map<String, String> headers) {
    _dio.options.headers.addAll(headers);
  }

  @override
  void setTimeout(Duration connectTimeout, Duration receiveTimeout, Duration sendTimeout) {
    _dio.options.connectTimeout = connectTimeout;
    _dio.options.receiveTimeout = receiveTimeout;
    _dio.options.sendTimeout = sendTimeout;
  }

  @override
  void addInterceptor(Interceptor interceptor) {
    _customInterceptors.add(interceptor);
    _addDefaultInterceptors(); // 重新应用拦截器
  }

  @override
  void removeInterceptor(Interceptor interceptor) {
    _customInterceptors.remove(interceptor);
    _addDefaultInterceptors(); // 重新应用拦截器
  }

  @override
  void clearInterceptors() {
    _customInterceptors.clear();
    _addDefaultInterceptors(); // 重新应用拦截器
  }

  @override
  Future<ApiResponse<T>> get<T>(
      String path, {
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
          () => _dio.get<T>(
        path,
        queryParameters: queryParameters,
        options: options,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> post<T>(
      String path, {
        dynamic data,
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
          () => _dio.post<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> put<T>(
      String path, {
        dynamic data,
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
          () => _dio.put<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> delete<T>(
      String path, {
        dynamic data,
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
          () => _dio.delete<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> patch<T>(
      String path, {
        dynamic data,
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
          () => _dio.patch<T>(
        path,
        data: data,
        queryParameters: queryParameters,
        options: options,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> upload<T>(
      String path, {
        required String filePath,
        required String fileKey,
        Map<String, dynamic>? data,
        ProgressCallback? onSendProgress,
        Options? options,
        String? requestId,
      }) async {
    final formData = FormData.fromMap({
      fileKey: await MultipartFile.fromFile(filePath),
      ...?data,
    });

    return _executeRequest<T>(
          () => _dio.post<T>(
        path,
        data: formData,
        options: options ?? Options(contentType: 'multipart/form-data'),
        onSendProgress: onSendProgress,
        cancelToken: _createCancelToken(requestId),
      ),
      requestId: requestId,
    );
  }

  @override
  Future<ApiResponse<T>> download<T>(
      String path, {
        required String savePath,
        ProgressCallback? onReceiveProgress,
        Map<String, dynamic>? queryParameters,
        Options? options,
        String? requestId,
      }) async {
    return _executeRequest<T>(
      () async {
        final resp = await _dio.download(
          path,
          savePath,
          queryParameters: queryParameters,
          options: options,
          onReceiveProgress: onReceiveProgress,
          cancelToken: _createCancelToken(requestId),
        );
        return Response<T>(
          data: resp.data as T,
          requestOptions: resp.requestOptions,
          statusCode: resp.statusCode,
          statusMessage: resp.statusMessage,
          headers: resp.headers,
          isRedirect: resp.isRedirect,
          redirects: resp.redirects,
          extra: resp.extra,
        );
      },
      requestId: requestId,
    );
  }

  // ============ 请求执行统一封装 ============

  Future<ApiResponse<T>> _executeRequest<T>(
      Future<Response<T>> Function() request, {
        String? requestId,
      }) async {
    try {
      final response = await request();

      return ApiResponse.success(
        response.data as T,
        statusCode: response.statusCode!,
        headers: response.headers.map,
      );
    } on DioException catch (e) {
      throw _handleDioError(e);
    } catch (e) {
      throw UnknownException('未知错误: $e');
    } finally {
      // 清理 cancel token
      if (requestId != null) {
        _cancelTokens.remove(requestId);
      }
    }
  }

  // ============ 错误处理 ============

  AppException _handleDioError(DioException error) {
    switch (error.type) {
      case DioExceptionType.connectionTimeout:
      case DioExceptionType.sendTimeout:
      case DioExceptionType.receiveTimeout:
        return TimeoutException('请求超时，请检查网络连接');

      case DioExceptionType.badResponse:
        return _handleResponseError(error.response!);

      case DioExceptionType.cancel:
        return NetworkException('请求已取消');

      case DioExceptionType.unknown:
        return NetworkException('网络连接失败，请检查网络设置');

      case DioExceptionType.badCertificate:
        return NetworkException('证书验证失败');

      case DioExceptionType.connectionError:
        return NetworkException('连接错误: ${error.message}');
    }
  }

  AppException _handleResponseError(Response response) {
    final statusCode = response.statusCode ?? 500;
    final message = response.data?['message'] ?? _getDefaultErrorMessage(statusCode);

    switch (statusCode) {
      case 400:
        return ValidationException(message);
      case 401:
        return AuthenticationException('身份验证失败');
      case 403:
        return ServerException('访问被拒绝', 403);
      case 404:
        return ServerException('资源未找到', 404);
      case 422:
        return ValidationException(message);
      case 429:
        return ServerException('请求过于频繁，请稍后重试', 429);
      case 500:
        return ServerException('服务器内部错误', 500);
      case 502:
      case 503:
      case 504:
        return ServerException('服务器暂时不可用', statusCode);
      default:
        return ServerException(message, statusCode);
    }
  }

  String _getDefaultErrorMessage(int statusCode) {
    switch (statusCode) {
      case 400:
        return '请求参数错误';
      case 401:
        return '未授权访问';
      case 403:
        return '访问被拒绝';
      case 404:
        return '请求的资源不存在';
      case 500:
        return '服务器内部错误';
      default:
        return '服务器错误: $statusCode';
    }
  }

  // ============ 请求取消 ============

  @override
  void cancelRequest(String requestId) {
    _cancelTokens[requestId]?.cancel('Request cancelled by user');
    _cancelTokens.remove(requestId);
  }

  @override
  void cancelAllRequests() {
    _cancelTokens.forEach((key, token) {
      token.cancel('All requests cancelled');
    });
    _cancelTokens.clear();
  }

  CancelToken _createCancelToken(String? requestId) {
    if (requestId == null) return CancelToken();

    final token = CancelToken();
    _cancelTokens[requestId] = token;
    return token;
  }

  // ============ 认证相关 ============

  @override
  void setAuthToken(String token) {
    _dio.options.headers['Authorization'] = 'Bearer $token';
  }

  @override
  void clearAuthToken() {
    _dio.options.headers.remove('Authorization');
  }

  // 添加认证拦截器（便捷方法）
  void addAuthInterceptor({
    required Future<String?> Function() getToken,
    required Future<String?> Function() refreshToken,
  }) {
    addInterceptor(AuthInterceptor(
      getToken: getToken,
      refreshToken: refreshToken,
    ));
  }

  // ============ 工具方法 ============

  @override
  bool isNetworkError(DioException error) {
    return error.type == DioExceptionType.connectionTimeout ||
        error.type == DioExceptionType.sendTimeout ||
        error.type == DioExceptionType.receiveTimeout ||
        error.type == DioExceptionType.connectionError ||
        error.type == DioExceptionType.unknown;
  }

  @override
  bool isServerError(int statusCode) {
    return statusCode >= 500 && statusCode < 600;
  }

  // ============ 资源释放 ============

  @override
  void dispose() {
    cancelAllRequests();
    _dio.close();
  }

  // ============ 其他便捷方法 ============

  // 获取当前配置
  BaseOptions get currentOptions => _dio.options;

  // 更新单个header
  void updateHeader(String key, String value) {
    _dio.options.headers[key] = value;
  }

  // 移除header
  void removeHeader(String key) {
    _dio.options.headers.remove(key);
  }

  // 获取当前所有请求ID
  List<String> get activeRequestIds => _cancelTokens.keys.toList();

  // 检查请求是否正在进行
  bool isRequestActive(String requestId) {
    return _cancelTokens.containsKey(requestId);
  }
}